home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / Tickle-4.0 (tcl) / tcl / extend / src.unused / tclXsignal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-26  |  38.5 KB  |  1,338 lines  |  [TEXT/MPS ]

  1. /*
  2.  * tclXsignal.c --
  3.  *
  4.  * Tcl Unix signal support routines and the signal and commands.
  5.  *-----------------------------------------------------------------------------
  6.  * Copyright 1991-1993 Karl Lehenbauer and Mark Diekhans.
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  11.  * Mark Diekhans make no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without express or
  13.  * implied warranty.
  14.  *-----------------------------------------------------------------------------
  15.  * $Id: tclXsignal.c,v 2.13 1993/08/31 23:03:20 markd Exp $
  16.  *-----------------------------------------------------------------------------
  17.  */
  18.  
  19. #include "tclExtdInt.h"
  20.  
  21.  
  22. #ifndef SIGCLD
  23. #   define SIGCLD SIGCHLD
  24. #endif
  25. #ifndef SIGCHLD
  26. #   define SIGCHLD SIGCLD
  27. #endif
  28.  
  29. #ifndef MAXSIG
  30. #  ifdef NSIG
  31. #    define MAXSIG NSIG
  32. #  else
  33. #    define MAXSIG 32
  34. #  endif
  35. #endif
  36.  
  37. /*
  38.  * Signal name table maps name to number.
  39.  */
  40.  
  41. #define SIG_NAME_MAX 7
  42.  
  43. static struct {char *name;
  44.         short num;
  45.        } sigNameTable [] = {
  46.     "HUP",     SIGHUP,
  47.     "INT",     SIGINT,
  48.     "QUIT",    SIGQUIT,
  49.     "ILL",     SIGILL,
  50.     "TRAP",    SIGTRAP,
  51.     "IOT",     SIGIOT,
  52. #ifdef SIGABRT
  53.     "ABRT",    SIGABRT,
  54. #endif
  55. #ifdef SIGEMT
  56.     "EMT",     SIGEMT,
  57. #endif
  58.     "FPE",     SIGFPE,
  59.     "KILL",    SIGKILL,
  60. #ifdef SIGBUS
  61.     "BUS",     SIGBUS,
  62. #endif
  63.     "SEGV",    SIGSEGV,
  64. #ifdef SIGSYS
  65.     "SYS",     SIGSYS,
  66. #endif
  67.     "PIPE",    SIGPIPE,
  68.     "ALRM",    SIGALRM,
  69.     "TERM",    SIGTERM,
  70.     "USR1",    SIGUSR1,
  71.     "USR2",    SIGUSR2,
  72.     "CLD",     SIGCLD,
  73.     "CHLD",    SIGCHLD,
  74. #ifdef SIGPWR
  75.     "PWR",     SIGPWR,
  76. #endif
  77. #ifdef SIGPOLL
  78.     "POLL",    SIGPOLL,
  79. #endif
  80. #ifdef SIGSTOP
  81.     "STOP",    SIGSTOP,
  82. #endif
  83. #ifdef SIGTSTP
  84.     "TSTP",    SIGTSTP,
  85. #endif
  86. #ifdef SIGCONT
  87.     "CONT",    SIGCONT,
  88. #endif
  89. #ifdef SIGTTIN
  90.     "TTIN",    SIGTTIN,
  91. #endif
  92. #ifdef SIGTTOU
  93.     "TTOU",    SIGTTOU,
  94. #endif
  95.     NULL,         -1};
  96.  
  97. #ifndef RETSIGTYPE
  98. #   define RETSIGTYPE void
  99. #endif
  100.  
  101. typedef RETSIGTYPE (*signalProcPtr_t) _ANSI_ARGS_((int));
  102.  
  103. /*
  104.  * Class of actions that can be set by the signal command.
  105.  */
  106. #define SIGACT_SET     1   /* Set the signal     */
  107. #define SIGACT_GET     2   /* Get the signal     */
  108. #define SIGACT_BLOCK   3   /* Block the signal   */
  109. #define SIGACT_UNBLOCK 4   /* Unblock the signal */
  110.  
  111. /*
  112.  * Defines if this is not Posix.
  113.  */
  114. #ifndef SIG_BLOCK
  115. #   define SIG_BLOCK       1
  116. #   define SIG_UNBLOCK     2
  117. #endif
  118.  
  119. /*
  120.  * Structure used to save error state of the interpreter.
  121.  */
  122. typedef struct {
  123.     char  *result;
  124.     char  *errorInfo;
  125.     char  *errorCode;
  126. } errState_t;
  127.  
  128. /*
  129.  * Table containing a interpreters and there Async handler cookie.
  130.  */
  131. typedef struct {
  132.     Tcl_Interp       *interp;
  133.     Tcl_AsyncHandler  handler;
  134. } interpHandler_t;
  135.  
  136. static interpHandler_t *interpTable = NULL;
  137. static int              interpTableSize  = 0;
  138. static int              numInterps  = 0;
  139.  
  140. /*
  141.  * A flag indicating that an "error" signal has occured.  This is used to
  142.  * flush interactive input in commands and is only cleared there.  Also an
  143.  * application-supplied function to call if a error signal occurs.  This
  144.  * normally flushes command input.
  145.  */
  146. int tclGotErrorSignal = FALSE;
  147. void (*tclErrorSignalProc) _ANSI_ARGS_((int signalNum)) = NULL;
  148.  
  149. /*
  150.  * Counters of signals that have occured but have not been processed.
  151.  */
  152. static unsigned signalsReceived [MAXSIG];
  153.  
  154. /*
  155.  * Table of commands to evaluate when a signal occurs.  If the command is
  156.  * NULL and the signal is received, an error is returned.
  157.  */
  158. static char *signalTrapCmds [MAXSIG];
  159.  
  160. /*
  161.  * Pointer to background error handler (normally NULL or Tk_BackgroundError).
  162.  */
  163. void (*tclSignalBackgroundError) _ANSI_ARGS_((Tcl_Interp *interp)) = NULL;
  164.  
  165. /*
  166.  * Prototypes of internal functions.
  167.  */
  168. static int
  169. SigNameToNum _ANSI_ARGS_((char *sigName));
  170.  
  171. static int
  172. GetSignalState _ANSI_ARGS_((int              signalNum,
  173.                             signalProcPtr_t *sigProcPtr));
  174.  
  175. static int
  176. SetSignalAction _ANSI_ARGS_((int             signalNum,
  177.                              signalProcPtr_t sigFunc));
  178.  
  179. static RETSIGTYPE
  180. TclSignalTrap _ANSI_ARGS_((int signalNum));
  181.  
  182. static int
  183. FormatTrapCode  _ANSI_ARGS_((Tcl_Interp  *interp,
  184.                              int          signalNum,
  185.                              Tcl_DString *command));
  186.  
  187. static errState_t *
  188. SaveErrorState _ANSI_ARGS_((Tcl_Interp *interp));
  189.  
  190. static void
  191. RestoreErrorState _ANSI_ARGS_((Tcl_Interp *interp,
  192.                                errState_t *errStatePtr));
  193.  
  194. static int
  195. EvalTrapCode _ANSI_ARGS_((Tcl_Interp *interp,
  196.                           int         signalNum));
  197.  
  198. static int
  199. ProcessASignal _ANSI_ARGS_((Tcl_Interp *interp,
  200.                             int         signalNum));
  201.  
  202. static int
  203. ParseSignalList _ANSI_ARGS_((Tcl_Interp *interp,
  204.                              char       *signalListStr,
  205.                              int         signalList []));
  206.  
  207. static char *
  208. SignalBlocked _ANSI_ARGS_((Tcl_Interp  *interp,
  209.                            int          signalNum));
  210.  
  211. static int
  212. GetSignalStates  _ANSI_ARGS_((Tcl_Interp *interp,
  213.                               int         signalListSize,
  214.                               int         signalList [MAXSIG]));
  215.  
  216. static int
  217. SetSignalStates  _ANSI_ARGS_((Tcl_Interp      *interp,
  218.                               int              signalListSize,
  219.                               int              signalList [MAXSIG],
  220.                               signalProcPtr_t  actionFunc,
  221.                               char            *command));
  222.  
  223. static int
  224. BlockSignals _ANSI_ARGS_((Tcl_Interp  *interp,
  225.                           int          action,
  226.                           int          signalListSize,
  227.                           int          signalList [MAXSIG]));
  228.  
  229. static void
  230. SignalCmdCleanUp _ANSI_ARGS_((ClientData  clientData,
  231.                               Tcl_Interp *interp));
  232.  
  233.  
  234. /*
  235.  *-----------------------------------------------------------------------------
  236.  *
  237.  * SigNameToNum --
  238.  *     Converts a UNIX signal name to its number, returns -1 if not found.
  239.  *     the name may be upper or lower case and may optionally have the 
  240.  *     leading "SIG" omitted.
  241.  *
  242.  *-----------------------------------------------------------------------------
  243.  */
  244. static int
  245. SigNameToNum (sigName)
  246.     char *sigName;
  247. {
  248.     char  sigNameUp [SIG_NAME_MAX+1];  /* Upshifted signal name */
  249.     char *sigNamePtr; 
  250.     int   idx;
  251.  
  252.     /*
  253.      * Copy and upshift requested name.
  254.      */
  255.  
  256.     if (strlen (sigName) > SIG_NAME_MAX)
  257.         return -1;   /* Name too long */
  258.  
  259.     Tcl_UpShift (sigNameUp, sigName);
  260.  
  261.     if (STRNEQU (sigNameUp, "SIG", 3))
  262.         sigNamePtr = &sigNameUp [3];
  263.     else
  264.         sigNamePtr = sigNameUp;
  265.  
  266.     for (idx = 0; sigNameTable [idx].num != -1; idx++)
  267.         if (STREQU (sigNamePtr, sigNameTable [idx].name))
  268.             break;
  269.  
  270.     return sigNameTable [idx].num;
  271. }
  272.  
  273. /*
  274.  *-----------------------------------------------------------------------------
  275.  *
  276.  * Tcl_KillCmd --
  277.  *     Implements the TCL kill command:
  278.  *        kill ?signal? proclist
  279.  *
  280.  * Results:
  281.  *  Standard TCL results, may return the UNIX system error message.
  282.  *
  283.  *-----------------------------------------------------------------------------
  284.  */
  285. int
  286. Tcl_KillCmd (clientData, interp, argc, argv)
  287.     ClientData  clientData;
  288.     Tcl_Interp *interp;
  289.     int     argc;
  290.     char      **argv;
  291. {
  292.     int    signalNum, idx, procId, procArgc, result = TCL_ERROR;
  293.     char **procArgv;
  294.  
  295.     if ((argc < 2) || (argc > 3)) {
  296.         Tcl_AppendResult (interp, tclXWrongArgs, argv [0], 
  297.                           " ?signal? processlist", (char *) NULL);
  298.         return TCL_ERROR;
  299.     }
  300.  
  301.     if (argc == 2)
  302.         signalNum = SIGTERM;
  303.     else {
  304.         if (!Tcl_StrToInt (argv[1], 0, &signalNum)) {
  305.             signalNum = SigNameToNum (argv[1]);
  306.         }
  307.         if ((signalNum < 0) || (signalNum > MAXSIG)) {
  308.             Tcl_AppendResult (interp, "invalid signal", (char *) NULL);
  309.             return TCL_ERROR;
  310.         }
  311.     }
  312.  
  313.     if (Tcl_SplitList (interp, argv [argc - 1], &procArgc, 
  314.                        &procArgv) != TCL_OK)
  315.         return TCL_ERROR;
  316.  
  317.     for (idx = 0; idx < procArgc; idx++) {
  318.  
  319.         if (Tcl_GetInt (interp, procArgv [idx], &procId) != TCL_OK)
  320.             goto exitPoint;
  321.  
  322.         if (kill ((pid_t) procId, signalNum) < 0) {
  323.             Tcl_AppendResult (interp, "pid ", procArgv [idx],
  324.                               ": ", Tcl_PosixError (interp), (char *) NULL);
  325.             goto exitPoint;
  326.         }
  327.      }
  328.  
  329.     result = TCL_OK;
  330. exitPoint:
  331.     ckfree ((char *) procArgv);
  332.     return result;
  333. }
  334.  
  335. /*
  336.  *-----------------------------------------------------------------------------
  337.  *
  338.  * GetSignalState --
  339.  *     Get the current state of the specified signal.
  340.  * Parameters:
  341.  *   o signalNum (I) - Signal number to query.
  342.  *   o sigProcPtr (O) - The signal function is returned here.
  343.  * Results
  344.  *   TCL_OK or TCL_ERROR (check errno).
  345.  *-----------------------------------------------------------------------------
  346.  */
  347. static int
  348. GetSignalState (signalNum, sigProcPtr)
  349.     int              signalNum;
  350.     signalProcPtr_t *sigProcPtr;
  351. {
  352. #ifdef HAVE_SIGACTION
  353.     struct sigaction currentState;
  354.  
  355.     if (sigaction (signalNum, NULL, ¤tState) < 0)
  356.         return TCL_ERROR;
  357.     *sigProcPtr = currentState.sa_handler;
  358.     return TCL_OK;
  359. #else
  360.     signalProcPtr_t  actionFunc;
  361.  
  362.     if (signalNum == SIGKILL)
  363.          actionFunc = SIG_DFL;
  364.     else
  365.         actionFunc = signal (signalNum, SIG_DFL);
  366.     if (actionFunc == SIG_ERR)
  367.         return TCL_ERROR;
  368.     if (actionFunc != SIG_DFL)
  369.         signal (signalNum, actionFunc);  /* reset */
  370.     *sigProcPtr = actionFunc;
  371.     return TCL_OK;
  372. #endif
  373. }
  374.  
  375. /*
  376.  *-----------------------------------------------------------------------------
  377.  *
  378.  * SetSignalAction --
  379.  *     Set the action to occur when a signal is received.
  380.  * Parameters:
  381.  *   o signalNum (I) - Signal number to query.
  382.  *   o sigFunc (O) - The signal function or SIG_DFL or SIG_IGN.
  383.  * Results
  384.  *   TCL_OK or TCL_ERROR (check errno).
  385.  *-----------------------------------------------------------------------------
  386.  */
  387. static int
  388. SetSignalAction (signalNum, sigFunc)
  389.     int             signalNum;
  390.     signalProcPtr_t sigFunc;
  391. {
  392. #ifdef HAVE_SIGACTION
  393.     struct sigaction newState;
  394.     
  395.     newState.sa_handler = sigFunc;
  396.     sigfillset (&newState.sa_mask);
  397.     newState.sa_flags = 0;
  398.  
  399.     if (sigaction (signalNum, &newState, NULL) < 0)
  400.         return TCL_ERROR;
  401.  
  402.     return TCL_OK;
  403. #else
  404.     if (signal (signalNum, sigFunc) == SIG_ERR)
  405.         return TCL_ERROR;
  406.     else
  407.         return TCL_OK;
  408. #endif
  409. }
  410.  
  411. /*
  412.  *-----------------------------------------------------------------------------
  413.  *
  414.  * TclSignalTrap --
  415.  *
  416.  *   Trap handler for UNIX signals.  Sets tells all registered interpreters
  417.  * that a trap has occured and saves the trap info.  The first interpreter to
  418.  * call it's async signal handler will process all pending signals.
  419.  *-----------------------------------------------------------------------------
  420.  */
  421. static RETSIGTYPE
  422. TclSignalTrap (signalNum)
  423.     int signalNum;
  424. {
  425.     int idx;
  426.  
  427.     /*
  428.      * Record the count of the number of this type of signal that has occured
  429.      * and tell all the interpreters to call the async handler when safe.
  430.      */
  431.     signalsReceived [signalNum]++;
  432.  
  433.     for (idx = 0; idx < numInterps; idx++)
  434.         Tcl_AsyncMark (interpTable [idx].handler);
  435.  
  436.     /*
  437.      * Flag used by command input functions to flush input.
  438.      */
  439.     if (signalTrapCmds [signalNum] == NULL) {
  440.         tclGotErrorSignal = TRUE;
  441.         if (tclErrorSignalProc != NULL)
  442.             (*tclErrorSignalProc) (signalNum);
  443.     }
  444. #ifndef HAVE_SIGACTION
  445.     /*
  446.      * For old-style Unix signals, the signal must be explictly re-enabled.
  447.      * Not done for SIGCHLD, as we would continue to the signal until the
  448.      * wait is done.  This is fixed by Posix signals and is not necessary under
  449.      * BSD, but it done this way for consistency.
  450.      */
  451.     if (signalNum != SIGCHLD) {
  452.         if (SetSignalAction (signalNum, TclSignalTrap) == TCL_ERROR)
  453.             panic ("TclSignalTrap bug");
  454.     }
  455. #endif
  456. }
  457.  
  458. /*
  459.  *-----------------------------------------------------------------------------
  460.  *
  461.  * SaveErrorState --
  462.  *  
  463.  *   Save the error state of the interpreter (result, errorInfo and errorCode).
  464.  *
  465.  * Parameters:
  466.  *   o interp (I) - The interpreter to save. Result will be reset.
  467.  * Returns:
  468.  *   A dynamically allocated structure containing all three strings,  Its
  469.  * allocated as a single malloc block.
  470.  *-----------------------------------------------------------------------------
  471.  */
  472. static errState_t *
  473. SaveErrorState (interp)
  474.     Tcl_Interp *interp;
  475. {
  476.     errState_t *errStatePtr;
  477.     char       *errorInfo, *errorCode, *nextPtr;
  478.     int         len;
  479.  
  480.     errorInfo = Tcl_GetVar (interp, "errorInfo", TCL_GLOBAL_ONLY);
  481.     errorCode = Tcl_GetVar (interp, "errorCode", TCL_GLOBAL_ONLY);
  482.  
  483.     len = sizeof (errState_t) + strlen (interp->result) + 1;
  484.     if (errorInfo != NULL)
  485.         len += strlen (errorInfo) + 1;
  486.     if (errorCode != NULL)
  487.         len += strlen (errorCode) + 1;
  488.  
  489.  
  490.     errStatePtr = (errState_t *) ckalloc (len);
  491.     nextPtr = ((char *) errStatePtr) + sizeof (errState_t);
  492.  
  493.     errStatePtr->result = nextPtr;
  494.     strcpy (errStatePtr->result, interp->result);
  495.     nextPtr += strlen (interp->result) + 1;
  496.  
  497.     errStatePtr->errorInfo = NULL;
  498.     if (errorInfo != NULL) {
  499.         errStatePtr->errorInfo = nextPtr;
  500.         strcpy (errStatePtr->errorInfo, errorInfo);
  501.         nextPtr += strlen (errorInfo) + 1;
  502.     }
  503.  
  504.     errStatePtr->errorCode = NULL;
  505.     if (errorCode != NULL) {
  506.         errStatePtr->errorCode = nextPtr;
  507.         strcpy (errStatePtr->errorCode, errorCode);
  508.         nextPtr += strlen (errorCode) + 1;
  509.     }
  510.  
  511.     Tcl_ResetResult (interp);
  512.     return errStatePtr;
  513. }
  514.  
  515. /*
  516.  *-----------------------------------------------------------------------------
  517.  *
  518.  * RestoreErrorState --
  519.  *  
  520.  *   Restore the error state of the interpreter that was saved by
  521.  * SaveErrorState.
  522.  *
  523.  * Parameters:
  524.  *   o interp (I) - The interpreter to save.
  525.  *   o errStatePtr (I) - Error state from SaveErrorState.  This structure will
  526.  *     be freed. 
  527.  * Returns:
  528.  *   A dynamically allocated structure containing all three strings,  Its
  529.  * allocated as a single malloc block.
  530.  *-----------------------------------------------------------------------------
  531.  */
  532. static void
  533. RestoreErrorState (interp, errStatePtr)
  534.     Tcl_Interp *interp;
  535.     errState_t *errStatePtr;
  536. {
  537.     Tcl_SetResult (interp, errStatePtr->result, TCL_VOLATILE);
  538.     Tcl_SetVar (interp, "errorInfo", errStatePtr->errorInfo, TCL_GLOBAL_ONLY);
  539.     Tcl_SetVar (interp, "errorCode", errStatePtr->errorCode, TCL_GLOBAL_ONLY);
  540.  
  541.     ckfree (errStatePtr);
  542. }
  543.  
  544. /*
  545.  *-----------------------------------------------------------------------------
  546.  *
  547.  * FormatTrapCode --
  548.  *     Format the signal name into the signal trap command.  Replacing %S with
  549.  * the signal name.
  550.  *
  551.  * Parameters:
  552.  *   o interp (I/O) - The interpreter to return errors in.
  553.  *   o signalNum (I) - The signal number of the signal that occured.
  554.  *   o command (O) - The resulting command adter the formatting.
  555.  *-----------------------------------------------------------------------------
  556.  */
  557. static int
  558. FormatTrapCode (interp, signalNum, command)
  559.     Tcl_Interp  *interp;
  560.     int          signalNum;
  561.     Tcl_DString *command;
  562. {
  563.     char  *signalName, *copyPtr, *scanPtr, prevChar;
  564.  
  565.     /*
  566.      * Force name to always be SIGCHLD, even if system defines only SIGCLD.
  567.      */
  568.     if (signalNum == SIGCHLD)
  569.         signalName = "SIGCHLD";
  570.     else
  571.         signalName = Tcl_SignalId (signalNum);
  572.  
  573.     Tcl_DStringInit (command);
  574.  
  575.     copyPtr = scanPtr = signalTrapCmds [signalNum];
  576.  
  577.     while (*scanPtr != '\0') {
  578.         if (*scanPtr != '%') {
  579.             scanPtr++;
  580.             continue;
  581.         }
  582.         if (scanPtr [1] == '%') {
  583.             scanPtr += 2;
  584.             continue;
  585.         }
  586.         Tcl_DStringAppend (command, copyPtr, (scanPtr - copyPtr));
  587.  
  588.         switch (scanPtr [1]) {
  589.           case 'S': {
  590.               Tcl_DStringAppend (command, signalName, -1);
  591.               break;
  592.           }
  593.           default:
  594.             goto badSpec;
  595.         }
  596.         scanPtr += 2;
  597.         copyPtr = scanPtr;
  598.     }
  599.     Tcl_DStringAppend (command, copyPtr, copyPtr - scanPtr);
  600.  
  601.     return TCL_OK;
  602.  
  603.     /*
  604.      * Handle bad % specification currently pointed to by scanPtr.
  605.      */
  606.   badSpec:
  607.     {
  608.         char badSpec [2];
  609.         
  610.         badSpec [0] = scanPtr [1];
  611.         badSpec [1] = '\0';
  612.         Tcl_AppendResult (interp, "bad signal trap command formatting ",
  613.                           "specification \"%", badSpec,
  614.                           "\", expected one of \"%%\" or \"%S\"",
  615.                           (char *) NULL);
  616.         return TCL_ERROR;
  617.     }
  618. }
  619.  
  620. /*
  621.  *-----------------------------------------------------------------------------
  622.  *
  623.  * EvalTrapCode --
  624.  *     Run code as the result of a signal.  The symbolic signal name is
  625.  * formatted into the command replacing %S with the symbolic signal name.
  626.  *
  627.  * Parameters:
  628.  *   o interp (I) - The interpreter to run the signal in. If an error
  629.  *     occures, then the result will be left in the interp.
  630.  *   o signalNum (I) - The signal number of the signal that occured.
  631.  * Return:
  632.  *   TCL_OK or TCL_ERROR.
  633.  *-----------------------------------------------------------------------------
  634.  */
  635. static int
  636. EvalTrapCode (interp, signalNum)
  637.     Tcl_Interp *interp;
  638.     int         signalNum;
  639. {
  640.     int          result;
  641.     Tcl_DString  command;
  642.  
  643.     Tcl_ResetResult (interp);
  644.  
  645.     /*
  646.      * Format the signal name into the command.  This also allows the signal
  647.      * to be reset in the command.
  648.      */
  649.  
  650.     result = FormatTrapCode (interp,
  651.                              signalNum,
  652.                              &command);
  653.     if (result == TCL_OK)
  654.         result = Tcl_GlobalEval (interp, 
  655.                                  command.string);
  656.  
  657.     Tcl_DStringFree (&command);
  658.  
  659.     if (result == TCL_ERROR) {
  660.         char errorInfo [64];
  661.  
  662.         sprintf (errorInfo, "\n    while executing signal trap code for %s%s",
  663.                  Tcl_SignalId (signalNum), " signal");
  664.         Tcl_AddErrorInfo (interp, errorInfo);
  665.  
  666.         return TCL_ERROR;
  667.     }
  668.     
  669.     Tcl_ResetResult (interp);
  670.     return TCL_OK;
  671. }
  672.  
  673. /*
  674.  *-----------------------------------------------------------------------------
  675.  *
  676.  * ProcessASignal --
  677.  *  
  678.  *   Do processing on the specified signal.
  679.  *
  680.  * Parameters:
  681.  *   o interp (O) - Result will contain the result of the signal handling
  682.  *     code that was evaled.
  683.  *   o signalNum - The signal to process.
  684.  * Returns:
  685.  *   TCL_OK or TCL_ERROR.
  686.  *-----------------------------------------------------------------------------
  687.  */
  688. static int
  689. ProcessASignal (interp, signalNum)
  690.     Tcl_Interp *interp;
  691.     int         signalNum;
  692. {
  693.     char *signalName;
  694.     int   result = TCL_OK;
  695.  
  696.     /*
  697.      * Either return an error or evaluate code associated with this signal.
  698.      * If evaluating code, call it for each time the signal occured.
  699.      */
  700.     if (signalTrapCmds [signalNum] == NULL) {
  701.         signalsReceived [signalNum] = 0;
  702.  
  703.         /*
  704.          * Force name to always be SIGCHLD, even if system defines only SIGCLD.
  705.          */
  706.         if (signalNum == SIGCHLD)
  707.             signalName = "SIGCHLD";
  708.         else
  709.             signalName = Tcl_SignalId (signalNum);
  710.  
  711.         Tcl_SetErrorCode (interp, "POSIX", "SIG", signalName, (char*) NULL);
  712.         Tcl_AppendResult (interp, signalName, " signal received", 
  713.                           (char *)NULL);
  714.         Tcl_SetVar (interp, "errorInfo", "", TCL_GLOBAL_ONLY);
  715.         result = TCL_ERROR;
  716.     } else {
  717.         while (signalsReceived [signalNum] > 0) {
  718.             (signalsReceived [signalNum])--;
  719.             result = EvalTrapCode (interp, signalNum);
  720.             if (result == TCL_ERROR)
  721.                 break;
  722.         }
  723.     }
  724.     return result;
  725. }
  726.  
  727. /*
  728.  *-----------------------------------------------------------------------------
  729.  *
  730.  * Tcl_ProcessSignals --
  731.  *  
  732.  *   Called by Tcl_Eval, etc to process pending signals in a safe state
  733.  * interpreter state.  This is often called just after a command completes.
  734.  * The results of the command are passed to this procedure and may be altered
  735.  * by it.  If trap code is specified for the signal that was received, then
  736.  * the trap will be executed, otherwise an error result will be returned
  737.  * indicating that the signal occured.  If an error is returned, clear the
  738.  * errorInfo variable.  This makes sure it exists and that it is empty,
  739.  * otherwise bogus or non-existant information will be returned if this
  740.  * routine was called somewhere besides Tcl_Eval.  If a signal was received
  741.  * multiple times and a trap is set on it, then that trap will be executed for
  742.  * each time the signal was received.
  743.  * 
  744.  * Parameters:
  745.  *   o clientData (I) - Not used.
  746.  *   o interp (I/O) - interp->result should contain the result for
  747.  *     the command that just executed.  This will either be restored or
  748.  *     replaced with a new result.  If this is NULL, the no interpreter
  749.  *     is directly available (i.e. Tk event loop).  In this case, the first
  750.  *     interpreter in internal interpreter table is used.  If an error occurs,
  751.  *     it is handled via the error handler registerd in the global variable
  752.  *     "tclSignalBackgroundError"
  753.  *   o cmdResultCode (I) - The integer result returned by the command that
  754.  *     Tcl_Eval just completed.  Should be TCL_OK if not called from
  755.  *     Tcl_Eval.
  756.  * Returns:
  757.  *   Either the original result code, an error result if one of the
  758.  *   trap commands returned an error, or an error indicating the
  759.  *   a signal occured.
  760.  *-----------------------------------------------------------------------------
  761.  */
  762. int
  763. Tcl_ProcessSignals (clientData, interp, cmdResultCode)
  764.     ClientData  clientData;
  765.     Tcl_Interp *interp;
  766.     int         cmdResultCode;
  767. {
  768.     Tcl_Interp *sigInterp;
  769.     errState_t *errStatePtr;
  770.     int         signalNum, result, idx;
  771.  
  772.     /*
  773.      * Get the interpreter is it wasn't supplied, if none is available,
  774.      * bail out.
  775.      */
  776.     if (interp == NULL) {
  777.         if (numInterps == 0)
  778.             return cmdResultCode;
  779.         sigInterp = interpTable [0].interp;
  780.     } else {
  781.         sigInterp = interp;
  782.     }
  783.  
  784.     errStatePtr = SaveErrorState (sigInterp);
  785.  
  786.     /*
  787.      * Process all signals.  Don't process any more if one returns an error.
  788.      */
  789.     result = TCL_OK;
  790.  
  791.     for (signalNum = 1; signalNum < MAXSIG; signalNum++) {
  792.         if (signalsReceived [signalNum] == 0)
  793.             continue;
  794.         result = ProcessASignal (sigInterp, signalNum);
  795.         if (result == TCL_ERROR)
  796.             break;
  797.     }
  798.  
  799.     /*
  800.      * Restore result and error state if we didn't get an error in signal
  801.      * handling.
  802.      */
  803.     if (result != TCL_ERROR) {
  804.         RestoreErrorState (sigInterp, errStatePtr);
  805.     } else {
  806.         ckfree (errStatePtr);
  807.         cmdResultCode = TCL_ERROR;
  808.     }
  809.  
  810.     /*
  811.      * Reset the signal received flag in case more signals are pending.
  812.      */
  813.     for (signalNum = 1; signalNum < MAXSIG; signalNum++) {
  814.         if (signalsReceived [signalNum] != 0)
  815.             break;
  816.     }
  817.     if (signalNum < MAXSIG) {
  818.         for (idx = 0; idx < numInterps; idx++)
  819.             Tcl_AsyncMark (interpTable [idx].handler);
  820.     }
  821.  
  822.     /*
  823.      * If we got an error and an interpreter was not supplied, call the
  824.      * background error handler (if available).  Otherwise, lose the error.
  825.      */
  826.     if ((result == TCL_ERROR) && (interp == NULL) &&
  827.         (tclSignalBackgroundError != NULL))
  828.         (*tclSignalBackgroundError) (sigInterp);
  829.  
  830.     return cmdResultCode;
  831. }
  832.  
  833. /*
  834.  *-----------------------------------------------------------------------------
  835.  *
  836.  * ParseSignalList --
  837.  *  
  838.  *   Parse a list of signal names or numbers.
  839.  * 
  840.  * Parameters:
  841.  *   o interp (O) - Interpreter for returning errors.
  842.  *   o signalListStr (I) - The Tcl list of signals to convert.
  843.  *   o signalList (O) - The list of converted signal numbers, must be
  844.  *     big enough to hold MAXSIG signals.
  845.  *     Tcl_Eval just completed.
  846.  * Returns:
  847.  *   The number of signals converted, or -1 if an error occures.
  848.  *-----------------------------------------------------------------------------
  849.  */
  850. static int
  851. ParseSignalList (interp, signalListStr, signalList)
  852.     Tcl_Interp *interp;
  853.     char       *signalListStr;
  854.     int         signalList [];
  855. {
  856.     char         **signalListArgv;
  857.     int            signalListSize, signalNum, idx;
  858.     int            result = -1;
  859.     char          *signalName;
  860.  
  861.     if (Tcl_SplitList (interp, signalListStr, &signalListSize, 
  862.                        &signalListArgv) != TCL_OK)
  863.         return -1;
  864.  
  865.     if (signalListSize > MAXSIG) {
  866.         Tcl_AppendResult (interp, "too many signals supplied in list",
  867.                           (char *) NULL);
  868.         goto exitPoint;
  869.     }
  870.  
  871.     if (signalListSize == 0) {
  872.         Tcl_AppendResult (interp, "signal list may not be empty",
  873.                           (char *) NULL);
  874.         goto exitPoint;
  875.     }
  876.  
  877.     for (idx = 0; idx < signalListSize; idx++) {
  878.         signalName = signalListArgv [idx];
  879.  
  880.         if (Tcl_StrToInt (signalName, 0, &signalNum))
  881.             signalName = Tcl_SignalId (signalNum);
  882.         else
  883.             signalNum = SigNameToNum (signalName);
  884.  
  885.         if (signalName == NULL) {
  886.             char numBuf [20];
  887.  
  888.             sprintf (numBuf, "%d", signalNum);
  889.             Tcl_AppendResult (interp, "invalid signal number: ",
  890.                               numBuf, (char *) NULL);
  891.             goto exitPoint;
  892.         }
  893.  
  894.         if ((signalNum < 1) || (signalNum > MAXSIG)) {
  895.             Tcl_AppendResult (interp, "invalid signal name: ",
  896.                               signalName, (char *) NULL);
  897.             goto exitPoint;
  898.         }
  899.         signalList [idx] = signalNum;
  900.     }
  901.  
  902.     result = signalListSize;
  903. exitPoint:
  904.     ckfree ((char *) signalListArgv);
  905.     return result;
  906.  
  907. }
  908.  
  909. /*
  910.  *-----------------------------------------------------------------------------
  911.  *
  912.  * SignalBlocked --
  913.  *     
  914.  *    Determine if a signal is blocked.  On non-Posix systems, always returns
  915.  * "0".
  916.  *
  917.  * Parameters::
  918.  *   o interp (O) - Error messages are returned in result.
  919.  *   o signalNum (I) - The signal to determine the state for.
  920.  * Returns:
  921.  *   NULL if an error occured, or a pointer to a static string of "1" if the
  922.  * signal is block, and a static string of "0" if it is not blocked.
  923.  *-----------------------------------------------------------------------------
  924.  */
  925. static char *
  926. SignalBlocked (interp, signalNum)
  927.     Tcl_Interp  *interp;
  928.     int          signalNum;
  929. {
  930. #ifdef HAVE_SIGACTION
  931.     int      idx;
  932.     sigset_t sigBlockSet;
  933.  
  934.     if (sigprocmask (SIG_BLOCK, NULL, &sigBlockSet)) {
  935.         interp->result = Tcl_PosixError (interp);
  936.         return NULL;
  937.     }
  938.     return sigismember (&sigBlockSet, signalNum) ? "1" : "0";
  939. #else
  940.     return "0";
  941. #endif
  942. }
  943.  
  944. /*
  945.  *-----------------------------------------------------------------------------
  946.  *
  947.  * GetSignalStates --
  948.  *     
  949.  *    Return a keyed list containing the signal states for the specified
  950.  * signals.
  951.  *
  952.  * Parameters::
  953.  *   o interp (O) - The list is returned in the result.
  954.  *   o signalListSize (I) - Number of signals in the signal list.
  955.  *   o signalList (I) - List of signals of requested signals.
  956.  * Returns:
  957.  *   TCL_OK or TCL_ERROR, with error message in interp.
  958.  *-----------------------------------------------------------------------------
  959.  */
  960. static int
  961. GetSignalStates (interp, signalListSize, signalList)
  962.     Tcl_Interp *interp;
  963.     int         signalListSize;
  964.     int         signalList [MAXSIG];
  965. {
  966.     int              idx, signalNum, actuallyDone = -1;
  967.     char            *stateKeyedList [MAXSIG];
  968.     char            *sigState [3], *sigEntry [2];
  969.     signalProcPtr_t  actionFunc;
  970.  
  971.     for (idx = 0; idx < signalListSize; idx ++) {
  972.         signalNum = signalList [idx];
  973.  
  974.         if (GetSignalState (signalNum, &actionFunc) == TCL_ERROR)
  975.             goto unixSigError;
  976.         
  977.         sigState [2] = NULL;
  978.         if (actionFunc == SIG_DFL)
  979.             sigState [0]  = "default";
  980.         else if (actionFunc == SIG_IGN)
  981.             sigState [0] = "ignore";
  982.         else if (actionFunc == TclSignalTrap) {
  983.             if (signalTrapCmds [signalNum] == NULL)
  984.                 sigState [0] = "error";
  985.             else {
  986.                 sigState [0] = "trap";
  987.                 sigState [2] = signalTrapCmds [signalNum];
  988.             }
  989.         } else {
  990.             sigState [0] = "unknown";
  991.         }
  992.  
  993.         sigState [1] = SignalBlocked (interp, signalNum);
  994.         if (sigState [1] == NULL)
  995.             goto unixSigError;
  996.  
  997.         sigEntry [0] = Tcl_SignalId (signalNum);
  998.         sigEntry [1] = Tcl_Merge ((sigState [2] == NULL) ? 2 : 3,
  999.                                   sigState);
  1000.  
  1001.         stateKeyedList [idx] = Tcl_Merge (2, sigEntry);
  1002.         ckfree (sigEntry [1]);
  1003.  
  1004.         actuallyDone = idx;
  1005.  
  1006.     }
  1007.     Tcl_SetResult (interp, Tcl_Merge (signalListSize, stateKeyedList),
  1008.                    TCL_DYNAMIC);
  1009.  
  1010.     for (idx = 0; idx <= actuallyDone; idx++)
  1011.         ckfree (stateKeyedList [idx]);
  1012.  
  1013.     return TCL_OK;
  1014.  
  1015. unixSigError:
  1016.     for (idx = 0; idx <= actuallyDone; idx++)
  1017.         ckfree (stateKeyedList [idx]);
  1018.  
  1019.     interp->result = Tcl_PosixError (interp);
  1020.     return TCL_ERROR;
  1021. }
  1022.  
  1023. /*
  1024.  *-----------------------------------------------------------------------------
  1025.  *
  1026.  * SetSignalStates --
  1027.  *     
  1028.  *    Set the signal state for the specified signals.  
  1029.  *
  1030.  * Parameters::
  1031.  *   o interp (O) - The list is returned in the result.
  1032.  *   o signalListSize (I) - Number of signals in the signal list.
  1033.  *   o signalList (I) - List of signals of requested signals.
  1034.  *   o actionFunc (I) - The function to run when the signal is received.
  1035.  *   o command (I) - If the function is the "trap" function, this is the
  1036.  *     Tcl command to run when the trap occurs.  Otherwise, NULL.
  1037.  * Returns:
  1038.  *   TCL_OK or TCL_ERROR, with error message in interp.
  1039.  *-----------------------------------------------------------------------------
  1040.  */
  1041. static int
  1042. SetSignalStates (interp, signalListSize, signalList, actionFunc, command)
  1043.     Tcl_Interp      *interp;
  1044.     int              signalListSize;
  1045.     int              signalList [MAXSIG];
  1046.     signalProcPtr_t  actionFunc;
  1047.     char            *command;
  1048.  
  1049. {
  1050.     int idx, signalNum;
  1051.  
  1052.     for (idx = 0; idx < signalListSize; idx ++) {
  1053.         signalNum = signalList [idx];
  1054.  
  1055.         if (signalTrapCmds [signalNum] != NULL) {
  1056.             ckfree (signalTrapCmds [signalNum]);
  1057.             signalTrapCmds [signalNum] = NULL;
  1058.         }
  1059.         if (SetSignalAction (signalNum, actionFunc) == TCL_ERROR)
  1060.             goto unixSigError;
  1061.  
  1062.         if (command != NULL)
  1063.             signalTrapCmds [signalNum] = ckstrdup (command);
  1064.     }
  1065.  
  1066.     return TCL_OK;
  1067.  
  1068. unixSigError:
  1069.     interp->result = Tcl_PosixError (interp);
  1070.     return TCL_ERROR;
  1071. }
  1072.  
  1073. /*
  1074.  *-----------------------------------------------------------------------------
  1075.  *
  1076.  * BlockSignals --
  1077.  *     
  1078.  *    Block or unblock the specified signals.  Returns an error if not a Posix
  1079.  * system.
  1080.  *
  1081.  * Parameters::
  1082.  *   o interp (O) - Error messages are returned in result.
  1083.  *   o action (I) - SIG_BLOCK or SIG_UNBLOCK.
  1084.  *   o signalListSize (I) - Number of signals in the signal list.
  1085.  *   o signalList (I) - List of signals of requested signals.
  1086.  * Returns:
  1087.  *   TCL_OK or TCL_ERROR, with error message in interp.
  1088.  *-----------------------------------------------------------------------------
  1089.  */
  1090. static int
  1091. BlockSignals (interp, action, signalListSize, signalList)
  1092.     Tcl_Interp  *interp;
  1093.     int          action;
  1094.     int          signalListSize;
  1095.     int          signalList [MAXSIG];
  1096. {
  1097. #ifdef HAVE_SIGACTION
  1098.     int      idx;
  1099.     sigset_t sigBlockSet;
  1100.  
  1101.     sigemptyset (&sigBlockSet);
  1102.  
  1103.     for (idx = 0; idx < signalListSize; idx ++)
  1104.         sigaddset (&sigBlockSet, signalList [idx]);
  1105.  
  1106.     if (sigprocmask (action, &sigBlockSet, NULL)) {
  1107.         interp->result = Tcl_PosixError (interp);
  1108.         return TCL_ERROR;
  1109.     }
  1110.  
  1111.     return TCL_OK;
  1112. #else
  1113.     interp->result = "Posix signals are not available on this system";
  1114.     return TCL_ERROR;
  1115. #endif
  1116. }
  1117.  
  1118. /*
  1119.  *-----------------------------------------------------------------------------
  1120.  *
  1121.  * Tcl_SignalCmd --
  1122.  *     Implements the TCL signal command:
  1123.  *         signal action siglist ?command?
  1124.  *
  1125.  * Results:
  1126.  *      Standard TCL results, may return the UNIX system error message.
  1127.  *
  1128.  * Side effects:
  1129.  *    Signal handling states may be changed.
  1130.  *-----------------------------------------------------------------------------
  1131.  */
  1132. static int
  1133. Tcl_SignalCmd (clientData, interp, argc, argv)
  1134.     char       *clientData;
  1135.     Tcl_Interp *interp;
  1136.     int         argc;
  1137.     char      **argv;
  1138. {
  1139.     int                  signalListSize, signalNum, idx;
  1140.     int                  signalList [MAXSIG], actionClass;
  1141.     char                *signalName;
  1142.     signalProcPtr_t      actionFunc;
  1143.     char                *command = NULL;
  1144.  
  1145.     if ((argc < 3) || (argc > 4)) {
  1146.         Tcl_AppendResult (interp, tclXWrongArgs, argv [0], 
  1147.                           " action signalList ?command?", (char *) NULL);
  1148.         return TCL_ERROR;
  1149.     }
  1150.  
  1151.     signalListSize = ParseSignalList (interp, argv [2], signalList);
  1152.     if (signalListSize < 0)    
  1153.         return TCL_ERROR;
  1154.  
  1155.     /*
  1156.      * Determine the action to take on all of the signals.
  1157.      */
  1158.     if (STREQU (argv [1], "trap")) {
  1159.         actionFunc = TclSignalTrap;
  1160.         actionClass = SIGACT_SET;
  1161.         if (argc != 4) {
  1162.             Tcl_AppendResult (interp, "command required for ",
  1163.                              "trapping signals", (char *) NULL);
  1164.             return TCL_ERROR;
  1165.         }
  1166.         command = argv [3];
  1167.     } else {
  1168.         if (STREQU (argv [1], "default")) {
  1169.             actionFunc  = SIG_DFL;
  1170.             actionClass = SIGACT_SET;
  1171.         } else if (STREQU (argv [1], "ignore")) {
  1172.             actionFunc = SIG_IGN;
  1173.             actionClass = SIGACT_SET;
  1174.         } else if (STREQU (argv [1], "error")) {
  1175.             actionFunc = TclSignalTrap;
  1176.             actionClass = SIGACT_SET;
  1177.         } else if (STREQU (argv [1], "get")) {
  1178.             actionClass = SIGACT_GET;
  1179.         } else if (STREQU (argv [1], "block")) {
  1180.             actionClass = SIGACT_BLOCK;
  1181.         } else if (STREQU (argv [1], "unblock")) {
  1182.             actionClass = SIGACT_UNBLOCK;
  1183.         } else {
  1184.             Tcl_AppendResult (interp, "invalid signal action specified: ", 
  1185.                               argv [1], ": expected one of \"default\", ",
  1186.                               "\"ignore\", \"error\", \"trap\", or \"get\", ",
  1187.                               "\"block\", \"unblock\"", (char *) NULL);
  1188.             return TCL_ERROR;
  1189.         }
  1190.         if (argc != 3) {
  1191.             Tcl_AppendResult (interp, "command may not be ",
  1192.                               "specified for \"", argv [1], "\" action",
  1193.                               (char *) NULL);
  1194.             return TCL_ERROR;
  1195.         }
  1196.     }
  1197.  
  1198.     /*
  1199.      * Process the specified action class.
  1200.      */
  1201.     switch (actionClass) {
  1202.       case SIGACT_SET:
  1203.         return SetSignalStates (interp, signalListSize, signalList,
  1204.                                 actionFunc, command);
  1205.       case SIGACT_GET:
  1206.         return GetSignalStates (interp, signalListSize, signalList);
  1207.       case SIGACT_BLOCK:
  1208.         return BlockSignals (interp, SIG_BLOCK, signalListSize, signalList);
  1209.       case SIGACT_UNBLOCK:
  1210.         return BlockSignals (interp, SIG_UNBLOCK, signalListSize, signalList);
  1211.     }
  1212.  
  1213. }
  1214.  
  1215. /*
  1216.  *-----------------------------------------------------------------------------
  1217.  *
  1218.  *  SignalCmdCleanUp --
  1219.  *
  1220.  *   Clean up the signal data structure when an interpreter is deleted. If
  1221.  * this is the last interpreter, clean up all tables.
  1222.  *
  1223.  * Parameters:
  1224.  *   o clientData (I) - Not used.
  1225.  *   o interp (I) - Interp that is being deleted.
  1226.  *-----------------------------------------------------------------------------
  1227.  */
  1228. static void
  1229. SignalCmdCleanUp (clientData, interp)
  1230.     ClientData  clientData;
  1231.     Tcl_Interp *interp;
  1232. {
  1233.     int  idx;
  1234.  
  1235.     for (idx = 0; idx < numInterps; idx++) {
  1236.         if (interpTable [idx].interp == interp)
  1237.             break;
  1238.     }
  1239.     if (idx == numInterps)
  1240.         panic ("signal interp lost");
  1241.  
  1242.     interpTable [idx] = interpTable [--numInterps];
  1243.  
  1244.     /*
  1245.      * If there are no more interpreters, clean everything up.
  1246.      */
  1247.     if (numInterps == 0) {
  1248.         ckfree (interpTable);
  1249.         interpTable = NULL;
  1250.         interpTableSize = 0;
  1251.  
  1252.         for (idx = 0; idx < MAXSIG; idx++) {
  1253.             if (signalTrapCmds [idx] != NULL) {
  1254.                 ckfree (signalTrapCmds [idx]);
  1255.                 signalTrapCmds [idx] = NULL;
  1256.             }
  1257.         }
  1258.     }
  1259. }
  1260.  
  1261. /*
  1262.  *-----------------------------------------------------------------------------
  1263.  *
  1264.  * Tcl_SetupSigInt --
  1265.  *    Set up SIGINT to the "error" state if the current state is default.
  1266.  * This is done because shells set SIGINT to ignore for background processes
  1267.  * so that they don't die on signals generated by the user at the keyboard.
  1268.  * Tcl only enables SIGINT catching if it is an interactive session.
  1269.  *-----------------------------------------------------------------------------
  1270.  */
  1271. void
  1272. Tcl_SetupSigInt ()
  1273. {
  1274.     signalProcPtr_t  actionFunc;
  1275.  
  1276.     if ((GetSignalState (SIGINT, &actionFunc) == TCL_OK) &&
  1277.         (actionFunc == SIG_DFL))
  1278.         SetSignalAction (SIGINT, TclSignalTrap);
  1279. }
  1280.  
  1281. /*
  1282.  *-----------------------------------------------------------------------------
  1283.  *
  1284.  * Tcl_InitSignalHandling --
  1285.  *      Initializes singal handling for a interpreter.
  1286.  *-----------------------------------------------------------------------------
  1287.  */
  1288. void
  1289. Tcl_InitSignalHandling (interp)
  1290.     Tcl_Interp *interp;
  1291. {
  1292.     int              idx;
  1293.     interpHandler_t *newTable;
  1294.  
  1295.     /*
  1296.      * If this is the first interpreter, set everything up.
  1297.      */
  1298.     if (numInterps == 0) {
  1299.         interpTableSize = 4;
  1300.         interpTable = (interpHandler_t *)
  1301.             ckalloc (sizeof (interpHandler_t) * interpTableSize);
  1302.  
  1303.         for (idx = 0; idx < MAXSIG; idx++) {
  1304.             signalsReceived [idx] = 0;
  1305.             signalTrapCmds [idx] = NULL;
  1306.         }
  1307.     }
  1308.  
  1309.     /*
  1310.      * If there is not room in this table for another interp, expand it.
  1311.      */
  1312.     if (numInterps == interpTableSize) {
  1313.         newTable = (interpHandler_t *)
  1314.             ckalloc (sizeof (interpHandler_t) * interpTableSize * 2);
  1315.         memcpy (newTable, interpTable,
  1316.                 sizeof (interpHandler_t) * interpTableSize);
  1317.         ckfree (interpTable);
  1318.         interpTable = newTable;
  1319.         interpTableSize *= 2;
  1320.     }
  1321.  
  1322.     /*
  1323.      * Add this interpreter to the list and set up a async handler.
  1324.      * Arange for clean up on the interpreter being deleted.
  1325.      */
  1326.     interpTable [numInterps].interp = interp;
  1327.     interpTable [numInterps].handler =
  1328.         Tcl_AsyncCreate (Tcl_ProcessSignals, (ClientData) NULL);
  1329.     numInterps++;
  1330.  
  1331.     Tcl_CallWhenDeleted (interp, SignalCmdCleanUp, (ClientData) NULL);
  1332.  
  1333.     Tcl_CreateCommand (interp, "kill", Tcl_KillCmd,
  1334.                        (ClientData) NULL, (void (*)()) NULL);
  1335.     Tcl_CreateCommand (interp, "signal", Tcl_SignalCmd,
  1336.                        (ClientData) NULL, (void (*)()) NULL);
  1337. }
  1338.